package com.lin.operatorlogrecord.content;

import com.lin.operatorlogrecord.entity.annotation.FieldIdentifyAnnotation;
import com.lin.operatorlogrecord.exception.OperatorLogException;

import java.lang.reflect.*;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: chenghao.lin
 * @Date: 2023/09/25
 * @Description: 构建操作日志内容元数据
 */
public class OperatorLogMetaDataBuilder {

    /**
     * 封装数据
     * @param object   目标对象
     * @param clazz    目标类
     * @return  封装类
     */
    public OperatorLogMetaData getChangeModel(Object object, Class<?> clazz) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        OperatorLogMetaData result = new OperatorLogMetaData();
        String name = null;
        String id = null;
        Map<String,String> fieldMap = new HashMap<>(16);
        Map<String, OperatorLogMetaData> subObjectMap = new HashMap<>(16);
        Map<String, List<OperatorLogMetaData>> list = new HashMap<>(16);
        Map<String,Integer> filedNameAndPriorityMap = new HashMap<>(16);
        // 遍历该类的所有变量
        for (Field field : clazz.getDeclaredFields()){
            field.setAccessible(true);
            // 判断该变量有无Comparator注解
            FieldIdentifyAnnotation comparator = field.getAnnotation(FieldIdentifyAnnotation.class);
            if (Objects.nonNull(comparator)) {
                // 变量的值
                Object filedValue = field.get(object);
                // 判断是否是唯一ID
                if (comparator.id()) {
                    id = String.valueOf(filedValue);
                } else {
                    // 字段名
                    String filedName = comparator.filedName();
                    if (comparator.isObjectName()) {
                        name = String.valueOf(filedValue);
                    }
                    // 显示优先级
                    filedNameAndPriorityMap.put(filedName, comparator.priority());
                    // 判断变量类型
                    switch (comparator.type()) {
                        case NORMAL:
                            fieldMap.put(filedName, String.valueOf(filedValue));
                            break;
                        case ENUM:
                            fieldMap.put(filedName, getDictionary((Integer) filedValue, comparator.dictionary()));
                            break;
                        case SUB_OBJECT:
                            fieldMap.putAll(getSubObject(filedNameAndPriorityMap,filedValue, field.getType()));
                            break;
                        case QUOTE_SUB_OBJECT:
                            subObjectMap.put(filedName, getChangeModel(filedValue, field.getType()));
                            break;
                        case SIMPLE_LIST:
                            fieldMap.put(filedName, getSimpleList((List<?>) filedValue));
                            break;
                        case COMPLEX_LIST:
                            list.put(filedName, getComplexList((List<?>) filedValue,  field.getGenericType()));
                            break;
                        default:
                            throw new OperatorLogException("没有这种类型的变量");
                    }
                }
            }
        }
        result.setId(id);
        result.setName(name);
        result.setFieldMap(fieldMap);
        result.setSubObjectMap(subObjectMap);
        result.setListMap(list);
        result.setFiledNameAndPriorityMap(filedNameAndPriorityMap);
        return result;

    }


    /**
     * 获取字典值
     */
    public String getDictionary(int coed, Class<?> dictionaryEnum) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        Object[] enumConstants = dictionaryEnum.getEnumConstants();
        if (Objects.isNull(enumConstants) || enumConstants.length == 0){
            throw new OperatorLogException("该类不是枚举类");
        } else {
            Method getValue = dictionaryEnum.getMethod("getValue", int.class);
            return (String) getValue.invoke(enumConstants[0], coed);
        }
    }

    /**
     * 把简单列表变成按字典排序的String
     */
    public String getSimpleList(List<?> simpleList){
        List<String> result = new ArrayList<>();
        for (Object object : simpleList){
            result.add(String.valueOf(object));
        }
        return result.stream().sorted().collect(Collectors.joining(","));
    }

    /**
     * 获取子对象是父类一部分的值
     */
    public Map<String,String> getSubObject(Map<String,Integer> filedNameAndPriorityMap,Object object, Class<?> clazz) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        Map<String,String> fieldMap = new HashMap<>(16);
        // 遍历该类的所有变量
        for (Field field : clazz.getDeclaredFields()){
            field.setAccessible(true);
            // 判断该变量有无Comparator注解
            FieldIdentifyAnnotation comparator = field.getAnnotation(FieldIdentifyAnnotation.class);
            if (Objects.nonNull(comparator)){
                // 变量的值
                Object filedValue = field.get(object);
                // 字段名
                String filedName = comparator.filedName();
                filedNameAndPriorityMap.put(filedName, comparator.priority());
                // 判断变量类型
                switch (comparator.type()){
                    case NORMAL:
                        fieldMap.put(filedName, String.valueOf(filedValue));
                        break;
                    case ENUM:
                        fieldMap.put(filedName, getDictionary((Integer) filedValue, comparator.dictionary()));
                        break;
                    case SUB_OBJECT:
                        fieldMap.putAll(getSubObject(filedNameAndPriorityMap,filedValue,field.getType()));
                        break;
                    case SIMPLE_LIST:
                        fieldMap.put(filedName, getSimpleList((List<?>) filedValue));
                        break;
                    default:
                        throw new OperatorLogException("没有这种类型的变量");

                }
            }
        }
        return fieldMap;
    }

    /**
     * 获取复杂列表的值
     */
    public List<OperatorLogMetaData> getComplexList(List<?> complexList, Type genericsType) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        // 得到泛型里的class类型对象
        ParameterizedType pt = (ParameterizedType) genericsType;
        Class<?> actualTypeArgument = (Class<?>)pt.getActualTypeArguments()[0];
        List<OperatorLogMetaData> result = new ArrayList<>();
        for (Object object : complexList){
            result.add(getChangeModel(object, actualTypeArgument));
        }
        return result;
    }
}
